import numpy as np


def create(n):
    """
    Create a n-dim Penalty I function

    :param n: dimensionality
    :return: x0, f, g, G
    """
    x0 = np.arange(1, n + 1, dtype=np.float64)
    alpha = 1e-5

    def get_f_last(x: np.ndarray):
        assert x.ndim == 1
        assert x.shape[0] == n
        return (x ** 2).sum() - 0.25

    def f(x: np.ndarray):
        fn_no_a, f_last = x - 1, get_f_last(x)
        return alpha * np.sum(fn_no_a ** 2) + f_last ** 2

    def g(x: np.ndarray):
        fn_no_a, f_last = x - 1, get_f_last(x)
        g1 = alpha * fn_no_a * 2
        g2 = f_last * x * 4
        return g1 + g2

    def h(x: np.ndarray):
        f_last = get_f_last(x)
        h1 = np.outer(x, x) * 8
        h_diag = np.full(n, alpha * 2 + f_last * 4, dtype=np.float64)
        return h1 + np.diag(h_diag)

    return x0, f, g, h
